﻿using System;
using Mono.Cecil;
using SPCAF.Sdk;
using SPCAF.Sdk.Model;
using SPCAFContrib.Entities.Consts;
using SPCAFContrib.Extensions;
using SPCAFContrib.Groups;
using SPCAFContrib.Rules.Code.Base;

namespace SPCAFContrib.Rules.Code
{
    [RuleMetadata(typeof(ContribCorrectnessGroup),
     CheckId = CheckIDs.Rules.Assembly.DoNotUseEntityEditorEntities,
     Help = CheckIDs.Rules.Assembly.DoNotUseEntityEditorEntities_HelpUrl,

     Message = "Do not use EntityEditor.Entities collection. Method: [{0}], Class:[{1}]",
     DisplayName = "Do not use EntityEditor.Entities collection.",
     Description = "It is not recommended to use the Entities property to get the selected entities, because using this sometimes causes unexpected behavior.",
     Resolution = "It’s much more reliable to use ResolvedEntities instead.",

     DefaultSeverity = Severity.Warning,
     SharePointVersion = new[] { "12", "14", "15" },
     Links = new[]
     {
         "EntityEditor.Entities property",
         "http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.entityeditor.entities.aspx",
         "EntityEditor.ResolvedEntities property",
         "http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.entityeditor.resolvedentities.aspx"
     }
     )]
    public class DoNotUseEntityEditorEntities : SearchPropertyRuleBase
    {
        protected override void PopulateTypeMap()
        {
            TargetTypeMap.Add(TypeKeys.EntityEditor, "Entities");
        }

        public override void Visit(AssemblyFileReferenceWSP assembly, NotificationCollection notifications)
        {
            if (assembly.AssemblyFileReference.AssemblyDefinition == null)
                assembly.AssemblyFileReference.AssemblyDefinition = AssemblyDefinition.ReadAssembly(assembly.AssemblyLocation);

            if (assembly.AssemblyHasExcluded()) return;

            EnsureTypeMap();

            assembly.OnPropertyUsageMatch(TargetTypeMap, (_instruction) =>
            {
                Mono.Cecil.MethodDefinition method = _instruction.MethodDefinition;
                this.OnMatch(assembly, _instruction, notifications, 
                    () =>
                {
                    return String.Format(this.MessageTemplate(), method.Name, method.DeclaringType.FullName);
                }, 
                    () =>
                {
                    return GetSummary(assembly, _instruction);
                });
            });
        }
    }
}
